package path;

import building.Cell;
import building.InfoAgent;
import building.InfoGame;

/**
 * The data map from our example game. This holds the state and context of each
 * tile on the map. It also implements the interface required by the path
 * finder. It's implementation of the path finder related methods add specific
 * handling for the types of units and terrain in the example game.
 * 
 */
public class GameMap {
	private InfoGame game;

	/** The map width in tiles */
	// public static final int WIDTH = 30;
	/** The map height in tiles */
	// public static final int HEIGHT = 30;

	// MEDIDAS DE NUESTRO SISTEMA VERDADERO
	public int WIDTH;
	public int HEIGHT;
	public int FLOORS;

	/*
	 * 1 Building 2 Street 3 RECYLCING_CENTER
	 */

	static public int FREE = 1;
	static public int FIRE = 2;
	static public int DOOR = 3;
	static public int OBJECT = 4;
	static public int STAIRS = 6;
	static public int SMOKE = 7;

	public static final int UNDISCOVERED = 10;
	/*
	 * Scout = 0 Harverst = 1
	 */

	public static final int EVACUATOR = 10;
	public static final int CIVILIAN = 5;
	public static final int FIREMAN = 8;
	public static final int PARAMEDIC = 9;

	/** The terrain settings for each tile in the map */
	private int[][][] terrain;
	/** The unit in each tile of the map */
	private int[][][] units;
	/** Indicator if a given tile has been visited during the search */
	private boolean[][][] visited;

	/**
	 * Create a new test map with some default configuration
	 */
	public GameMap(InfoGame infoGame) {

		this.game = infoGame;

		WIDTH = this.game.getMap().width;
		HEIGHT = this.game.getMap().length;
		FLOORS = this.game.getMap().nfloor;
		terrain = new int[FLOORS][WIDTH][HEIGHT];
		units = new int[FLOORS][WIDTH][HEIGHT];
		visited = new boolean[FLOORS][WIDTH][HEIGHT];

		// System.out.println("long mappppp" + this.game.getMap().length);
		for (int f = 0; f < FLOORS; f++) {
			for (int c = 0; c < WIDTH; c++) {
				for (int r = 0; r < HEIGHT; r++) {

					if (game.getCell(r, c, f) != null) {
						// System.out.println(this.game.getCell(x,
						// y).getCellType());
						// System.out.println(game.getCell(r,
						// c).isThereAnAgent());
						// private char garbageType = '-'; //G=Glass, P=Plastic,
						// M=Metal, P=Paper

						terrain[f][c][r] = game.getCell(r, c, f).getCellType();

						// NO SURTEN ELS AGENTS RECONEGUTS
						if (this.game.getCell(r, c, f).isThereAnAgent() == true) {
							// System.out.println("AGENT TROBATTTT");
							if (this.game.getCell(r, c, f).getAgent()
									.getAgentType() == InfoAgent.CIVILIAN) {
								units[f][c][r] = CIVILIAN;
								// System.out.println("SCOUTTTT");
							} else if (this.game.getCell(r, c, f).getAgent()
									.getAgentType() == InfoAgent.EVACUATOR)
							// SERA 1 corresponent HARVESTER
							{
								units[f][c][r] = EVACUATOR;
								// System.out.println("HARVESTER");
							} else if (this.game.getCell(r, c, f).getAgent()
									.getAgentType() == InfoAgent.PARAMEDIC)
							// SERA 1 corresponent HARVESTER
							{
								units[f][c][r] = PARAMEDIC;
								// System.out.println("HARVESTER");
							} else {
								units[f][c][r] = FIREMAN;
							}
						}

					} else {

						terrain[f][c][r] = FREE;

					}

				}
			}
		}

		// printMap();

	}

	/**
	 * Clear the array marking which tiles have been visted by the path finder.
	 */

	public void clearVisited(int f) {
		for (int x = 0; x < getWidthInTiles(); x++) {
			for (int y = 0; y < getHeightInTiles(); y++) {
				visited[f][x][y] = false;
			}
		}
	}

	/**
	 * @see TileBasedMap#visited(int, int)
	 */
	public boolean visited(int x, int y, int f) {
		return visited[f][x][y];
	}

	/**
	 * Get the terrain at a given location
	 * 
	 * @param x
	 *            The x coordinate of the terrain tile to retrieve
	 * @param y
	 *            The y coordinate of the terrain tile to retrieve
	 * @return The terrain tile at the given location
	 */
	public int getTerrain(int x, int y, int f) {
		return terrain[f][x][y];
	}

	public void setTerrain(int x, int y, int f) {
		// System.out.print("Posicioooooo Origen Destiiiiiiiiiii "+terrain[x][y]+
		// " " + x+ " " + y);
		terrain[f][x][y] = FREE;
		// System.out.print("Posicioooooo Destiiiiiiiiiii "+terrain[x][y] +" " +
		// x+ " " + y);
	}

	/**
	 * Get the unit at a given location
	 * 
	 * @param x
	 *            The x coordinate of the tile to check for a unit
	 * @param y
	 *            The y coordinate of the tile to check for a unit
	 * @return The ID of the unit at the given location or 0 if there is no unit
	 */
	public int getUnit(int x, int y, int f)
			throws java.lang.ArrayIndexOutOfBoundsException {
		try {
			return units[f][x][y];
		} catch (java.lang.ArrayIndexOutOfBoundsException e) {
			System.err.printf("Game map Index out of bounds " + x + " " + y);
			return 0;
		}
	}

	/**
	 * Set the unit at the given location
	 * 
	 * @param x
	 *            The x coordinate of the location where the unit should be set
	 * @param y
	 *            The y coordinate of the location where the unit should be set
	 * @param unit
	 *            The ID of the unit to be placed on the map, or 0 to clear the
	 *            unit at the given location
	 */
	public void setUnit(int x, int y, int unit, int f) {
		System.out.println("unit set " + x + y + f + " unit" + unit);
		units[f][x][y] = unit;
	}

	/**
	 * @see TileBasedMap#blocked(Mover, int, int)
	 */

	// Tenir en compte k s0haura de generar dos alternaitvas de bloked...
	// Incorporar una variable booleana! per calcular les dos possibilitats
	public boolean blocked(UnitMover mover, int x, int y, int option, int f) {
		// System.out.println("BLOCKED " + "x" + x +"y" + y + "f" + f);
		// if theres a unit at the location, then it's blocked
		// System.out.println("getUnit" + getUnit(x,y, f));
		if (option==2 && getUnit(x, y, f) != 0 && (getUnit(x, y, f) != EVACUATOR && getUnit(x, y, f) !=CIVILIAN)) 
			return true;
	
		if (getUnit(x, y, f) != 0 && option!=2) 
			return true;
	
		int unit = ((UnitMover) mover).getType();
		// System.out.print(unit + "unita trovata");

		// civilians and agents can only move throught free cells

		if (unit == CIVILIAN) {
			// System.out.println("Game map:sono un civilian"+unit+"terrain"
			// +terrain[f][x][y] );
			if ((terrain[f][x][y] == FREE) || (terrain[f][x][y] == STAIRS)
					|| (terrain[f][x][y] == SMOKE))

				return false;
		}

		if (unit == EVACUATOR) {
			// System.out.println("Game map:sono un evacuator"+unit
			// +"terrain"+terrain[f][x][y] );
			if ((terrain[f][x][y] == FREE) || (terrain[f][x][y] == STAIRS)
					|| (terrain[f][x][y] == SMOKE))

				return false;
		}

		
	
		// unknown unit so everything blocks
		// System.out.println("blockedd");
		return true;
	}

	/**
	 * @see TileBasedMap#getCost(Mover, int, int, int, int)
	 */
	public float getCost(UnitMover mover, int sx, int sy, int sf, int tx,
			int ty, int tf) {

		if (game.getCell(tx, ty, tf).getCellType() == Cell.SMOKE) {
			// System.out.println("passing trough smoke" +game.getCell(tx,ty,
			// tf).getCellType());
			return 5;
		}

		return 1;
	}

	/**
	 * @see TileBasedMap#getHeightInTiles()
	 */
	public int getHeightInTiles() {
		return WIDTH;
	}

	/**
	 * @see TileBasedMap#getWidthInTiles()
	 */
	public int getWidthInTiles() {
		return HEIGHT;
	}

	public int getLevels() {
		return FLOORS;
	}

	public void setLevels(int fLOORS) {
		FLOORS = fLOORS;
	}

	/**
	 * @see TileBasedMap#pathFinderVisited(int, int)
	 */
	public void pathFinderVisited(int x, int y, int f) {
		visited[f][x][y] = true;
	}

	public void printMap() {
		for (int f = 0; f < FLOORS; f++) {
			for (int r = 0; r < HEIGHT; r++) {
				for (int c = 0; c < WIDTH; c++) {
					switch (terrain[f][c][r]) {
					case 2:
						System.out.print("&");
						break;
					case 1:
						System.out.print("_");
						break;
					case 3:
						System.out.print("*");
						break;
					case 10:
						System.out.print("?");
						break;
					case 4:
						System.out.print("*");
						break;
					case 6:
						System.out.print("/");
						break;
					case 7:
						System.out.print("/");
						break;
					}
				}
			}
			System.out.println("");
		}
	}
}
